package com.nebula.wxlogin.controller.wx;

import com.gb.common.result.Result;
import com.gb.common.result.ResultGenerator;
import com.gb.common.utils.wx.HttpUtil;
import com.gb.common.utils.wx.PayCommonUtil;
import com.gb.common.utils.wx.w.WXPayUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 微信支付是否让用户微信登录
 * 微信登录的话就可以直接拿到openid了
 * @Author: llq
 * @Date: 2019/10/11
 */
@Slf4j
@RestController
@RequestMapping("/wx/jsApi")
public class WxPayJsApiController {
    @Value("${wx.app.notifyUrl}")
    String notify_Url;
    @Value("${wx.app.createOrderURL}")
    String createOrderURL;
    @Value("${wx.app.key}")
    String key;
    @Value("${wx.app.appId}")
    String appId;
    @Value("${wx.app.mchId}")
    String mchId;



    /**
     * 微信jsapi支付
     *  TODO openid需要去获取一下
     *   orderidentifier  定单编号
     *   openid  去数据库查到
     * @return
     * @throws Exception
     */
    @RequestMapping("/pay")
    public Result wxPayJsApi(HttpServletRequest request) throws Exception {
        String openid = "";
        Map<String, String> result = new HashMap<>();
        result.put("success", "false");
        try {
            // TODO 付款金额，单位分，必填，测试建议使用1分钱
            String total_fee = "1";
            // 获取发起电脑的ip ,必须传正确的用户端IP
            String spbill_create_ip = HttpUtil.getRealIp(request);

//            HashMap<String, String> map = Maps.newHashMap();
//            WXPay.fillRequestData(map);

            // appid
            String appid = appId;
            // 商业号
            String mch_id = mchId;
            // key

            // 随机数
            String nonce_str = WXPayUtil.generateNonceStr();
            // 价格 注意：默认单位是分
            String order_price = total_fee;
//            new BigDecimal(total_fee).multiply(new BigDecimal(100)).toString().split("\\.")[0];
            // 商家订单号
            String out_trade_no = "1234567890";
            // 回调接口
            String notify_url = notify_Url;
            // 交易类型,JSAPI支付只能为JSAPI
            String trade_type = "JSAPI";
            // TODO 订单名称,这里是商品的名称
            String body = "皮卡丘";
            // 设置订单参数
            SortedMap<String, String> packageParams = new TreeMap<>();
            packageParams.put("appid", appid);
            packageParams.put("mch_id", mch_id);
            packageParams.put("nonce_str", nonce_str);
            packageParams.put("body", body);
            packageParams.put("out_trade_no", out_trade_no);
            packageParams.put("total_fee", order_price);
            packageParams.put("spbill_create_ip", spbill_create_ip);
            packageParams.put("notify_url", notify_url);
            packageParams.put("trade_type", trade_type);
            //支付人的微信公众号对应的唯一标识 openid
            //由于用户微信登录了直接去数据库查出 openid
            packageParams.put("openid", openid);
            //签名
            String sign = WXPayUtil.generateSignature(packageParams, key);
            packageParams.put("sign", sign);
            //调用微信统一下单接口，拿到预支付交易回话表示prepay_id
            /* 调用统一下单接口后的返回xml
               要出现支付界面 需要在前端设置
             <xml>
              <return_code><![CDATA[SUCCESS]]></return_code>
              <return_msg><![CDATA[OK]]></return_msg>
              <appid><![CDATA[wx2421b1c4370ec43b]]></appid>
              <mch_id><![CDATA[10000100]]></mch_id>
              <nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str>
              <openid><![CDATA[oUpF8uMuAJO_M2pxb1Q9zNjWeS6o]]></openid>
              <sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign>
              <result_code><![CDATA[SUCCESS]]></result_code>
              <prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id>
              <trade_type><![CDATA[JSAPI]]></trade_type>
            </xml>*/
//            Map<String, String> map = wxPay.unifiedOrder(packageParams);
            String requestXML = WXPayUtil.mapToXml(packageParams);
            String resXml = HttpUtil.postData(createOrderURL, requestXML);
            Map map = WXPayUtil.xmlToMap(resXml);
            //预支付交易回话表示prepay_id
            Object prepay_id = map.get("prepay_id");
            result.put("appId", appid);
            SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
            Date date=new Date();
            String dateStr=sdf.format(date);
            result.put("timestamp", dateStr);
            result.put("nonceStr", WXPayUtil.generateNonceStr());
            result.put("package", "prepay_id="+prepay_id);
            result.put("signType", "MD5");
            String paySign = WXPayUtil.generateSignature(result, key);
            result.put("paySign",paySign);
        } catch (Exception e) {
            log.error(e.getMessage());
            result.put("msg", "支付失败");
        }
        return ResultGenerator.genSuccessResult(result);
    }

    /**
     * 执行回调 确认支付后处理事件 例如添加金额到数据库等操作
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping("/payNotify")
    public void wxNotify(HttpServletRequest request, HttpServletResponse response)throws Exception {
        String xmlMsg = readData(request);
        Map params = WXPayUtil.xmlToMap(xmlMsg);
        if (null == params){
            throw new NullPointerException("微信服务器未返回任何数据!");
        }
        // 过滤空 设置 TreeMap
        SortedMap<Object, Object> ToEmptyParams = new TreeMap<>();
        Iterator it = params.keySet().iterator();
        while (it.hasNext()) {
            String parameter = (String) it.next();
            String parameterValue = params.get(parameter)+"";
            String v = "";
            if (null != parameterValue) {
                v = parameterValue.trim();
            }
            System.out.println("value==============="+v);
            ToEmptyParams.put(parameter, v);
        }
        log.debug(ToEmptyParams.toString());
        // 账号信息key
        //同步返回给微信结果，通知处理成功/失败
        String resXml = "";
        //判断签名是否正确
        if(PayCommonUtil.isTenpaySign("UTF-8", ToEmptyParams,key)) {
            // ------------------------------
            // 处理业务开始
            // 更新已支付金额/状态码/用户经验值（等级)/添加积分
            // ------------------------------
            if ("SUCCESS".equals(ToEmptyParams.get("return_code"))) {
                try {
                    //////////执行自己的业务逻辑////////////////
                    //trade_type 交易类型(H5支付)/bank_type 付款银行/time_end 支付完成时间/cash_fee 现金支付金额/userid
                    //支付成功后的业务逻辑
                    //微信支付的商户号
                    String mchid = (String) ToEmptyParams.get("mchid");
                    //微信支付的订单金额 ,将分转换成元-实际支付金额:元
                    String total_fee = new BigDecimal((String) ToEmptyParams.get("total_fee")).divide(new BigDecimal(100)).toString();
                    //商家订单号
                    String out_trade_no = (String) ToEmptyParams.get("out_trade_no");
                    //微信支付订单号
                    String transaction_id = (String) ToEmptyParams.get("transaction_id");

                    System.out.println("mchid : " + mchid);
                    System.out.println("total_fee ：" + total_fee);
                    System.out.println("out_trade_no :" + out_trade_no);
                    System.out.println("transaction_id :" + transaction_id);

                    //通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
                    resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                            + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
                    System.out.println("=============支付成功============");
                } catch (Exception e){
                    // 退款逻辑没写
                    e.printStackTrace();
                    log.error(e.getMessage());
                }
                ////////// 执行自己的业务逻辑////////////////
            } else {
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" +
                        "<return_msg><![CDATA[支付失败]]></return_msg>" + "</xml> ";
                System.out.println("==============支付失败============");
            }
        }else {
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[通知签名验证失败]]></return_msg>" + "</xml> ";
            log.debug("通知签名验证失败");
            // 支付失败
        }
        BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
        out.write(resXml.getBytes());
        out.flush();
        out.close();
    }



    public static String readData(HttpServletRequest request) {
        BufferedReader br = null;
        try {
            StringBuilder result = new StringBuilder();
            br = request.getReader();
            for (String line; (line=br.readLine())!=null;) {
                if (result.length() > 0) {
                    result.append("\n");
                }
                result.append(line);
            }

            return result.toString();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        finally {
            if (br != null){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
